package com.yc.springboot.biz;

import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Set;

@Service
public class UserBiz {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 登录
     * date yyyy-mm-dd
     */
    public void login(String username, String password, String date) {
        // 省略用户登录的业务逻辑
        String key = "online_" + date;
        long pos = username.hashCode();
        // 设置位图值 true
        // redisTemplate.opsForValue().setBit(key, pos, true);
        // 以回调方式设置在线状态, 与后续计算保持一致
        redisTemplate.execute((RedisCallback<? extends Object>) con -> {
            con.setBit(key.getBytes(), pos, true);
            return null;
        });
    }

    /**
     * 判断用户是否持续在线( 活跃用户 )
     *
     * @param username
     * @return
     */
    public boolean isOnline(String username) {
        // 获取在线位图的 key 值
        final Set<byte[]> keys = redisTemplate.execute((RedisCallback<Set<byte[]>>) con -> {
            return con.keys("online_*".getBytes());
        });
        // 回调执行
        boolean ret = redisTemplate.execute((RedisCallback<Boolean>) con -> {
            // Redis 连接对象
            String destKey = "is_online_boolean";
            // 请二维数组
            byte[][] byteKeys = new byte[keys.size()][];
            int i = 0;
            for (byte[] key : keys) {
                byteKeys[i++] = key;
            }
            // 逻辑与运算, 结果保存在 destKey 中
            con.bitOp(RedisStringCommands.BitOperation.AND,
                    destKey.getBytes(),
                    byteKeys);
            // 返回结果
            return con.getBit(destKey.getBytes(), username.hashCode());
        });
        return ret;
    }

    /**
     * 判断用户是否持续在线( 活跃用户 )
     *
     * @param username
     * @return
     */
    public long countOnline(String username) {

        // 获取在线位图的 key 值
        final Set<byte[]> keys = redisTemplate.execute((RedisCallback<Set<byte[]>>) con -> {
            return con.keys("online_*".getBytes());
        });
        // 回调执行
        long ret = redisTemplate.execute((RedisCallback<Long>) con -> {
            // Redis 连接对象
            String destKey = "is_online_boolean";
            // 请二维数组
            byte[][] byteKeys = new byte[keys.size()][];
            int i = 0;
            for (byte[] key : keys) {
                byteKeys[i++] = key;
            }
            // 逻辑与运算, 结果保存在 destKey 中
            con.bitOp(RedisStringCommands.BitOperation.AND,
                    destKey.getBytes(),
                    byteKeys);
            // 返回结果
            return con.bitCount(destKey.getBytes());
        });
        return ret;
    }

}
